#ifndef __MY_UTIL__
#define __MY_UTIL__
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <memory>
#include <unistd.h>
#include "bundle.h"
#include <experimental/filesystem>
#include <jsoncpp/json/writer.h>
#include <jsoncpp/json/reader.h>
#include <iconv.h>
using namespace std;
namespace fs = std::experimental::filesystem;
namespace Cloud
{
    class FileUtil // 文件工具类
    {
    private:
        string _filename;

    public:
        FileUtil(const string &filename) : _filename(filename)
        {
        }
        struct stat st;     // 存储文件信息
        uint64_t FileSize() // 获取文件大小
        {
            if (stat(_filename.c_str(), &st) < 0)
            {
                cout << "get Filesize fail!" << endl;
                return -1;
            }

            return st.st_size;
            // try
            // {
            //     auto size = fs::file_size(_filename);
            //     std::cout << "File size: " << size << " bytes\n";
            //     return size;
            // }
            // catch (const fs::filesystem_error &e)
            // {
            //     std::cerr << "Error: " << e.what() << '\n';
            //     // 可以在这里添加更多的错误处理逻辑
            // }
            // return fs::file_size(_filename);
        }

        time_t LastMTime() // 获取文件最后一次修改时间
        {
            if (stat(_filename.c_str(), &st) < 0)
            {
                cout << "get fileModifi time fail!" << endl;
                return -1;
            }
            return st.st_mtim.tv_sec;
        }

        time_t LastATime() // 获取文件最后一次访问时间
        {
            if (stat(_filename.c_str(), &st) < 0)
            {
                cout << "get fileaccess time fail!" << endl;
                return -1;
            }
            return st.st_atim.tv_sec;
        }

        string GetFileName() // 获取文件路径下的文件名
        {
            // size_t pos = _filename.find_last_of("/");
            // if (pos == string::npos)
            // {
            //     return _filename;
            // }
            // return _filename.substr(pos + 1);
            return fs::path(_filename).filename().string();
        }

        bool GetPosLen(string *content, size_t pos, size_t len) // 读取指定位置文件内容
        {
            size_t fszie = FileSize();
            if (len > fszie)
            {
                cout << "get file len  fail" << endl;
                return false;
            }
            ifstream ifs(_filename, ios::binary);
            if (ifs.is_open() == false)
            {
                cout << "read open file fail" << endl;
                return false;
            }
            ifs.seekg(pos, ios::beg);
            content->resize(len); // 减少扩容带来的内存分配和复制的开销
            ifs.read(&(*content)[0], len);
            if (ifs.good() == false) // 判断文件是否读取
            {
                cout << "GetPosLen file read fail" << endl;
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }

        bool GetCentent(string *content) // 读取文件
        {
            return GetPosLen(content, 0, FileSize());
        }

        bool SetCentent(string &content) // 写入文件
        {
            ofstream ofs;
            ofs.open(_filename, ios::binary);
            if (ofs.is_open() == false)
            {
                cout << "write open file fail" << endl;
                return false;
            }
            ofs.write(&content[0], content.size());
            if (ofs.good() == false) // 判断文件是否写入成功
            {
                cout << "SetCentent file read fail" << endl;
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }

        bool Compress(const string &packname) // 压缩文件
        {
            // 1、获取源文件数据
            string body;
            if (GetCentent(&body) == false)
            {
                cout << "Compress get file connect failed" << endl;
                return false;
            }
            // 2、将数据进行压缩
            string packed = bundle::pack(bundle::LZIP, body); // 压缩文件

            // 3、将压缩的数据写入指定文件
            Cloud::FileUtil fu(packname);
            if (fu.SetCentent(packed) == false) // 将压缩后的文件写入指定文件中
            {
                cout << "Compress write file failed" << endl;
                return false;
            }
            return true;
        }

        bool UnCompress(string &Unpackname) // 解压文件
        {
            string body;
            if (GetCentent(&body) == false)
            {
                cout << "UnCompress get file connect failed" << endl;
                return false;
            }

            string unpacked = bundle::unpack(body); // 解压文件

            Cloud::FileUtil fu(Unpackname);

            if (fu.SetCentent(unpacked) == false) // 将解压后的文件写入指定文件中
            {
                cout << "UnCompress write file failed" << endl;
                return false;
            }
            return true;
        }

        bool Exists() // 判断文件是否存在
        {
            return fs::exists(_filename);
        }

        bool CreateDirectory() // 创建目录
        {
            if (Exists())
                return true;
            if (!fs::create_directories(_filename))
            {
                cout << "CreateDirectory is fail" << endl;
            }
            return true;
        }
        bool ScanDirectory(vector<string> *array) // 扫描目录中的文件
        {
            for (auto &e : fs::directory_iterator{_filename})
            {
                if (fs::is_directory(e)) // 判断当前文件是否为目录
                    continue;
                array->push_back(fs::path(e).relative_path().string()); // 将当前文件的相对路径添加到vector
            }
            return true;
        }
        bool Remove()
        {
            if (Exists() == false)
            {
                return true;
            }
            // remove(GetFileName().c_str());
            remove(_filename.c_str());
            return true;
        }
    };
    class JsonUtil // json工具类
    {
    public:
        static bool Serialize(const Json::Value &root, string *str)
        {
            Json::StreamWriterBuilder swb;
            unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
            stringstream val;
            if (sw->write(root, &val) != 0)
            {
                cout << "Serialize failed" << endl;
                return false;
            }
            *str = val.str();
            return true;
        }
        static bool UnSerialize(const string &str, Json::Value *root)
        {
            Json::CharReaderBuilder crb;
            unique_ptr<Json::CharReader> cr(crb.newCharReader());
            string error;
            bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), root, &error);
            if (ret == false)
            {
                cout << "parse error:" << error << endl;
                return false;
            }
            return false;
        }
    };
}

#endif